package cn.jimmie.learn.viewArt.ball;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.util.TypedValue;
import android.view.View;

import cn.jimmie.learn.viewArt.R;


/**
 * function : 浮球视图
 * 由于 该视图是添加到 WindowManager中, 因此无需使用 xml形式的布局方式
 *
 * <p> Create Time: 2018年12月31日 09:16 </p>
 * <p> @author Jimmie.Qian  </p>
 */

@SuppressLint("ViewConstructor")
public class AssistBallView extends View {
    public final static int LEFT = 1;
    public final static int RIGHT = 2;
    public final static int TOP = 3;
    public final static int BOTTOM = 4;

    public final static float NONE_PCT = 0;
    // √2/2
    private final static float ROOT2 = 0.7071067812f;
    private final static int MAX_PING = 9999;
    // 各样式和资源的控制
    final Conf mConf;
    private final Paint mPaint;
    int mOrientation = LEFT;
    // 旋转角度
    private int mAngle;
    private float mPct;
    private boolean needTranslation;
    private boolean isLock;
    private boolean isPing;
    private boolean hasRedDot;
    private boolean isHide;
    private int mLevel;
    private int mBgAlpha = 255;

    public AssistBallView(Context context, Conf conf) {
        super(context);
        this.mConf = conf;

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setTextSize(conf.DIMEN.text);
    }

    public static Builder creator(Context context) {
        return new Builder(context);
    }

    void rotate(int angle, float pct) {
        if (pct == mPct) return;

        needTranslation = false;
        mPct = pct;
        // 对锁定状态,且ping状态下的情况做处理
        if (isLock && isPing) {
            mAngle = 0;
            if (pct > NONE_PCT) {
                needTranslation = true;
            }
        }
        // 对ping值,非锁定状态下,位置在上方的单独处理
        else if (!isLock && isPing && mOrientation == TOP) {
            mPct = pct;
            mAngle = 0;
            if (pct > NONE_PCT) {
                needTranslation = true;
            }
        }
        // 通用情况
        else if (angle != mAngle) {
            this.mAngle = angle;
        }
        // 靠近边缘时,布局大小发生变化
        if (pct >= NONE_PCT) {
            invalidate();
        }
    }

    void alpha(int alpha) {
        if (mBgAlpha != alpha) {
            mBgAlpha = alpha;
            invalidate();
        }
    }

    public void setLock(boolean lock) {
        if (isLock != lock) {
            isLock = lock;
            invalidate();
        }
    }

    void setHide(boolean hide) {
        if (hide != isHide) {
            isHide = hide;
            invalidate();
        }
    }

    public void setRedDot(boolean visibility) {
        if (hasRedDot != visibility) {
            hasRedDot = visibility;
            invalidate();
        }
    }

    public void setPing(int ping) {
        isPing = ping > 0;

        if (ping > MAX_PING) ping = MAX_PING;
        int now = Integer.parseInt(mConf.RES.pingTx);
        if (now != ping) {
            if (ping < mConf.DIMEN.edgeInNormalWarning) {
                mLevel = 0;
            } else if (ping < mConf.DIMEN.edgeInWarningDanger) {
                mLevel = 1;
            } else {
                mLevel = 2;
            }
            mConf.RES.pingTx = String.valueOf(ping);
            if (mPct > NONE_PCT && isLock) {
                needTranslation = true;
                mAngle = 0;
            }
            invalidate();
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int size = mConf.DIMEN.size;
        int halfSize = size / 2;

        if (mPct > NONE_PCT) {
            if (mOrientation == TOP) {
                canvas.rotate(mAngle, halfSize, halfSize * (1 - mPct));
                canvas.translate(0, -halfSize * (mPct));
            } else if (mOrientation == LEFT) {
                canvas.rotate(mAngle, halfSize * (1 - mPct), halfSize);
                canvas.translate(-halfSize * mPct, 0);
            } else if (mOrientation == RIGHT) {
                canvas.rotate(mAngle, halfSize * (1 + mPct), halfSize);
                canvas.translate(halfSize * mPct, 0);
            } else {
                canvas.translate(0, halfSize * mPct);
            }
        }

        Drawable bg;
        // 显示Ping + lock
        if (isPing && isLock) bg = mConf.RES.levelsDw[mLevel];
            // 显示Ping
        else if (isPing) bg = mConf.RES.levelsDw[mLevel];
            // 显示lock
        else if (isLock) bg = mConf.RES.lockDw;
            // 显示logo
        else bg = mConf.RES.logosDw[isHide ? 1 : 0];

        bg.setBounds(0, 0, size, size);
        bg.setAlpha(mBgAlpha);
        bg.draw(canvas);

        // ping and lock
        if (isPing && isLock) {
            // 锁定平移
            if (needTranslation) {
                int smallLockSize = mConf.DIMEN.smallLock;
                int left = halfSize - smallLockSize / 2;
                int top = (int) (halfSize - smallLockSize * 1.3);
                float v = 0.8f * smallLockSize;
                Drawable smallLockDrawable = mConf.RES.smallLockDw;
                switch (mOrientation) {
                    case LEFT:
                        left = (int) (left + v * mPct);
                        top = (int) (top + v * mPct);
                        break;
                    case RIGHT:
                        left = (int) (left - v * mPct);
                        top = (int) (top + v * mPct);
                        break;
                    case TOP:
                        v = v * 2;
                        top = (int) (top + v * mPct);
                }
                smallLockDrawable.setBounds(left, top, left + smallLockSize, top + smallLockSize);
                smallLockDrawable.draw(canvas);
            } else {
                int smallLockSize = mConf.DIMEN.smallLock;
                mConf.RES.smallLockDw.setBounds(halfSize - smallLockSize / 2, (int) (halfSize - smallLockSize * 1.3),
                    halfSize + smallLockSize / 2, (int) (halfSize - 0.3 * smallLockSize));
                mConf.RES.smallLockDw.draw(canvas);

                // 下行字
                mPaint.setColor(mConf.COLOR.text);
                Paint.FontMetrics fs = mPaint.getFontMetrics();
                float fontHeight = fs.descent - fs.ascent;
                canvas.drawText(mConf.RES.pingTx, halfSize, halfSize + fontHeight * 2 / 3, mPaint);
            }
        }
        // ping and unlock
        else if (isPing) {
            mPaint.setColor(mConf.COLOR.text);
            Paint.FontMetrics fs = mPaint.getFontMetrics();
            float fontHeight = fs.descent - fs.ascent;
            // 在上方是不需要旋转,需要平移
            if (needTranslation) {
                float top = halfSize - fontHeight / 6;
                top = top + fontHeight * mPct;
                canvas.drawText(mConf.RES.pingTx, halfSize, top, mPaint);
            } else {
                // 上行字
                canvas.drawText(mConf.RES.pingTx, halfSize, halfSize - fontHeight / 6, mPaint);
                // 下行字
                canvas.drawText(mConf.RES.unitTx, halfSize, halfSize + fontHeight * 2 / 3, mPaint);
            }
        }
        // 绘制小红点
        if (hasRedDot) {
            int redRadius = mConf.DIMEN.redRadius;
            mPaint.setColor(Color.RED);
            float redX = halfSize - (halfSize - redRadius) * ROOT2;
            float redY = halfSize - (halfSize - redRadius) * ROOT2;
            if (needTranslation && mOrientation == LEFT) {
                redX = halfSize + (redRadius - halfSize + (halfSize - redRadius) * 2 * mPct) * ROOT2;
            } else if (needTranslation && mOrientation == TOP) {
                redY = halfSize + (redRadius - halfSize + (halfSize - redRadius) * 2 * mPct) * ROOT2;
            }
            canvas.drawCircle(redX, redY, redRadius, mPaint);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int size = mConf.DIMEN.size;
        setMeasuredDimension(size, size);
    }

    public int getSize() {
        return mConf.DIMEN.size;
    }

    // ==================== config ====================

    public static class Builder {
        private final Context ctx;
        private final Conf conf;

        private Builder(Context ctx) {
            this.ctx = ctx;
            conf = new Conf();
            init();
        }

        private void init() {
            float dp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                1, ctx.getResources().getDisplayMetrics());
            float sp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                1, ctx.getResources().getDisplayMetrics());
            conf.DIMEN.size = (int) (60 * dp);
            conf.DIMEN.text = (int) (9 * sp);
            conf.DIMEN.redRadius = (int) (4 * dp);
            conf.DIMEN.smallLock = (int) (8 * dp);
            conf.DIMEN.initPosition = 0;
            conf.DIMEN.edgeInNormalWarning = 3000;
            conf.DIMEN.edgeInWarningDanger = 6000;

            conf.COLOR.text = Color.WHITE;
            Drawable[] bgDws = new Drawable[3];
            bgDws[0] = ContextCompat.getDrawable(ctx, R.drawable.m4399_ope_assist_pop_greenball);
            bgDws[1] = ContextCompat.getDrawable(ctx, R.drawable.m4399_ope_assist_pop_orangeball);
            bgDws[2] = ContextCompat.getDrawable(ctx, R.drawable.m4399_ope_assist_pop_redball);

            Drawable[] logosDw = new Drawable[2];
            logosDw[0] = ContextCompat.getDrawable(ctx, R.drawable.m4399_ope_assist_pop_logo_one_normal);
            logosDw[1] = ContextCompat.getDrawable(ctx, R.drawable.m4399_ope_assist_pop_logo_one_hide);

            conf.RES.levelsDw = bgDws;
            conf.RES.logosDw = logosDw;
            conf.RES.lockDw = ContextCompat.getDrawable(ctx, R.drawable.m4399_ope_assist_pop_lock);
            conf.RES.smallLockDw = ContextCompat.getDrawable(ctx, R.drawable.m4399_ope_assist_pop_small_lock);
            conf.RES.pingTx = "-1";
            conf.RES.unitTx = "ms";
        }

        Builder setLogoStyle(int style) {
            Drawable[] logosDw = new Drawable[2];
            if (style == 1) {
                logosDw[0] = ContextCompat.getDrawable(ctx, R.drawable.m4399_ope_assist_pop_logo_two_normal);
                logosDw[1] = ContextCompat.getDrawable(ctx, R.drawable.m4399_ope_assist_pop_logo_two_hide);
            } else if (style == 2) {
                logosDw[0] = ContextCompat.getDrawable(ctx, R.drawable.m4399_ope_assist_pop_logo_three_normal);
                logosDw[1] = ContextCompat.getDrawable(ctx, R.drawable.m4399_ope_assist_pop_logo_three_hide);
            } else if (style == 3) {
                logosDw[0] = ContextCompat.getDrawable(ctx, R.drawable.m4399_ope_assist_pop_logo_four_normal);
                logosDw[1] = ContextCompat.getDrawable(ctx, R.drawable.m4399_ope_assist_pop_logo_four_hide);
            } else logosDw = conf.RES.logosDw;
            conf.RES.logosDw = logosDw;
            return this;
        }

        Builder setBallPosition(int position) {
            conf.DIMEN.initPosition = position;
            return this;
        }

        Builder setPingEdges(int edgeInNormalWarning, int edgeInWarningDanger) {
            conf.DIMEN.edgeInNormalWarning = edgeInNormalWarning;
            conf.DIMEN.edgeInWarningDanger = edgeInWarningDanger;
            return this;
        }

        public AssistScrollerView create() {
            return new AssistScrollerView(ctx, conf);
        }
    }

    static class Conf {
        final Color COLOR;
        final Dimen DIMEN;
        final Res RES;

        Conf() {
            COLOR = new Color();
            DIMEN = new Dimen();
            RES = new Res();
        }

        // 颜色
        class Color {
            int text;
        }

        // 尺寸
        // Ts 表示文字大小尺寸
        class Dimen {
            int size;               // 宽高一致
            int text;               // 文字大小
            int redRadius;          // 红点半径
            int smallLock;          // 小个的lock图标大小
            int initPosition;       // 初始化的位置 left | right | top | bottom
            int edgeInNormalWarning;// ping值边界(正常和警告之间)
            int edgeInWarningDanger;// ping值边界(警告和危险之间)
        }

        // 资源
        // Tx 表示文字
        // Dw 表示Drawable
        class Res {
            Drawable lockDw;
            Drawable smallLockDw;
            Drawable[] levelsDw;
            Drawable[] logosDw;
            String unitTx;
            String pingTx;
        }
    }
}
